﻿using Hydrogen.MathExt.Expression.Functions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;

namespace Hydrogen.MathExt.Expression.Tests
{
    [TestClass]
    public class UnitTest1
    {
        Dictionary<string, double> variables = new Dictionary<string, double>
        {
            {"x", 5}, {"y", 3}, {"radius", 10},
            {"height", 7.5}, {"mass", 2.5}, {"angle", System.Math.PI/4}
        };

        public const double PI = System.Math.PI;
        public const double E = System.Math.E;

        public Func<double, double, double> Pow = (a, b) => System.Math.Pow(a, b);
        public Func<double, double> Sin = a => System.Math.Sin(a);
        public Func<double, double> Cos = a => System.Math.Cos(a);
        public Func<double, double> Log10 = a => System.Math.Log10(a);
        public Func<double, double> Ln = a => System.Math.Log(a);
        public Func<double, double> Sqrt = a => System.Math.Sqrt(a);

        [TestMethod]
        public void TestMethod1()
        {
            var expression = 2 + 3 * 4;
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("2 + 3 * 4", variables));
        }
        [TestMethod]
        public void TestMethod2()
        {
            var expression = variables["x"] * variables["y"];
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("x * y", variables));
        }
        [TestMethod]
        public void TestMethod3_1()
        {
            var expression = Sin(3.14);
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("sin(3.14)", variables));
        }
        [TestMethod]
        public void TestMethod3()
        {
            var expression = Sin(PI / 2) + variables["x"];
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("sin(pi/2) + x", variables));
        }
        [TestMethod]
        public void TestMethod4()
        {
            var expression = Sqrt(variables["x"] * variables["x"] + variables["y"] * variables["y"]);
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("sqrt(x^2 + y^2)", variables));
        }
        [TestMethod]
        public void TestMethod5()
        {
            var expression = Pow(2, variables["y"]) + 4 * variables["x"];
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("2^y + 4 * x", variables));
        }
        [TestMethod]
        public void TestMethod6()
        {
            var expression = Log10(100) + Ln(Pow(E, 2)) * variables["mass"];
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("log(100) + ln(e^2) * mass", variables));
        }
        [TestMethod]
        public void TestMethod7()
        {
            var expression = 3.5 * (variables["height"] + 4.9);
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("3.5 * (height + 4.9)", variables));
        }
        [TestMethod]
        public void TestMethod8()
        {
            var expression = 1e-2 * 100 + variables["radius"];
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("1e-2 * 100 + radius", variables));
        }
        [TestMethod]
        public void TestMethod9()
        {
            var expression = 2 * Sin(PI / 2) * variables["x"];
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("2sin(pi/2) * x", variables));
        }
        [TestMethod]
        public void TestMethod10()
        {
            var expression = 3 * (2 + variables["y"]);
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("3(2+y)", variables));
        }
        [TestMethod]
        public void TestMethod11()
        {
            var expression = (variables["x"] + variables["y"]) * variables["mass"];
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("(x+y)mass", variables));
        }
        [TestMethod]
        public void TestMethod12()
        {
            var expression = PI * variables["radius"];
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("pi * radius", variables));
        }
        [TestMethod]
        public void TestMethod13()
        {
            var expression = Sqrt(Pow(variables["radius"], 2)) + 2 * Cos(0);
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("sqrt(radius^2) + 2cos(0)", variables));
        }
        [TestMethod]
        public void TestMethod14()
        {
            var expression = variables["mass"] * Pow(variables["height"], 2) / 2;
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("mass * height^2 / 2", variables));
        }
        [TestMethod]
        public void TestMethod15()
        {
            var expression = Sin(variables["angle"]) * Cos(variables["angle"]);
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("sin(angle) * cos(angle)", variables));
        }
        [TestMethod]
        public void TestMethod16()
        {
            var expression = Sqrt(Pow(variables["radius"], 2) - Pow(variables["x"], 2));
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("sqrt(radius^2 - x^2)", variables));
        }

        [TestMethod]
        public void TestMethod17()
        {
            var expression = 800;
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("500+max(1,100)+200", variables));
        }
        [TestMethod]
        public void TestMethod18()
        {
            var a = MathExpressionEvaluator.Evaluate("random01");
            var b = MathExpressionEvaluator.Evaluate("random01");

            Console.WriteLine($"a={a}\tb={b}");
            Assert.AreNotEqual(a, b);
        }
        [TestMethod]
        public void TestMethod19()
        {
            var a = MathExpressionEvaluator.Evaluate("randomint(0,1000)");
            var b = MathExpressionEvaluator.Evaluate("randomint(0,1000)");

            Console.WriteLine($"a={a}\tb={b}");
            if (a == b)
                Console.WriteLine("整型随机数，有一定概率得到两个相同的数。如果出现这种情况，就再测试一次");
            Assert.AreNotEqual(a, b);
        }

        [TestMethod]
        public void TestMethod20()
        {
            var expression = -2 * 10;
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("-2 * 10", variables));
        }
        [TestMethod]
        public void TestMethod21()
        {
            var expression = 10 * (-2);
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("10*(-2)", variables));
        }
        [TestMethod]
        public void TestMethod22()
        {
            var expression = Math.Sin(-10) + 10;
            Assert.AreEqual(expression, MathExpressionEvaluator.Evaluate("Sin(-10)+10", variables));
        }
        [TestMethod]
        public void TestMethod23()
        {
            var expression = MathExpressionEvaluator.GetExpressionEvaluator("Sin(-10)+10");

            var expressionResult = Math.Sin(-10) + 10;
            Assert.AreEqual(expressionResult, expression.Evaluate(variables));
        }
    }
}
